﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Bitirme.DAL.Entities;
using Bitirme.DAL.Enum;

namespace Bitirme.Controllers
{
    public class ScheduleInterProjects /// Biten işe yeni atama yapılırken, iş bitmişse atama yapma !!!!
    {

        List<Project> projects;
        ProjectHandler projectHandler;
        EmployeeHandler employeeHandler;
        AssignmentHandler assignmentHandler;
        List<Employee> employeeList;
        String _Result = String.Empty;
        List<Assignment> assignmentList;
        Project tempProject;

        public string Result
        {
            get { return _Result; }
            set { _Result = value; }
        }


        public ScheduleInterProjects(List<Project> projects) {

            projectHandler = new ProjectHandler();
            employeeHandler = new EmployeeHandler();
            assignmentHandler = new AssignmentHandler();
            this.projects = projects;
            employeeList = employeeHandler.GetAllEmployeesWithSkills();
            assignmentList = new List<Assignment>();
            tempProject = new Project();
            List<Assignment> databaseAssignments;

            List<WorkPackage> packageList = new List<WorkPackage>();

            tempProject.StartDate = projects[0].StartDate; 
            tempProject.EndDate = projects[0].EndDate; // bunlar referans oldu sorun olabilir.

            foreach (Project projectItem in projects)
            {
                databaseAssignments = assignmentHandler.GetAssignmentsByProjectID(projectItem.ID);
                if (DateTime.Compare(projectItem.StartDate, tempProject.StartDate) > 0)
                    projectItem.StartDate = tempProject.StartDate;
                if (DateTime.Compare(projectItem.EndDate, tempProject.EndDate) < 0)
                    projectItem.EndDate = tempProject.EndDate;
                foreach (WorkPackage package in projectItem.PackageList)
                {
                    if (package.PackageState == State.Pasive)
                    {// sadece o an çalışmayan paketleri assign edilmek üzere listeye alacak
                        packageList.Add(package);
                    }
                    else if (package.PackageState == State.Active)
                    {
                        foreach (Assignment assign in databaseAssignments)
                        {
                            if (assign.WorkPackage.ID == package.ID && DateTime.Compare(tempProject.StartDate, assign.EndDate) <= 0)
                            {

                                tempProject.StartDate = assign.EndDate.AddDays(1);
                            }
                        }
                    }
                }
            }
            tempProject.PackageList = packageList;

        }

        protected List<Employee> findProperEmployeesForWorkPackage(WorkPackage package)
        {
            List<Employee> employees = new List<Employee>();
            foreach (Employee employee in employeeList)
            {
                foreach (KeyValuePair<Capability, SkillLevel> capability in employee.Skills)
                {
                    if ((package.Requirement.RequirementCapability.Name).ToLower() == (capability.Key.Name).ToLower())
                    {
                        employees.Add(employee);
                        break;
                    }
                }
            }
            return employees;
        }

        public List<ScheduledWorkPackages> createWorkPackageQuery(List<WorkPackage> workPackages)
        {

            ScheduledWorkPackages scheduledWorkPackage;
            List<ScheduledWorkPackages> tempQuery = new List<ScheduledWorkPackages>();
            List<ScheduledWorkPackages> scheduleWorkPackageQuery = new List<ScheduledWorkPackages>();

            foreach (WorkPackage package in workPackages)
            {

                scheduledWorkPackage = new ScheduledWorkPackages(package);
                scheduledWorkPackage.ProperEmployees = findProperEmployeesForWorkPackage(package);
                scheduledWorkPackage.InitialStartDate = tempProject.StartDate;
                
                //scheduledWorkPackage.Assignment = assignmentHandler.GetAssignmentsByWorkPackageID(package.ID);
                tempQuery.Add(scheduledWorkPackage);
                /*
                if (scheduledWorkPackage.Assignment.Count > 0)
                    scheduledWorkPackage.isAlreadyAssigned = true;
                foreach (Assignment assigned in scheduledWorkPackage.Assignment)
                {
                    //assigned start date daha erken bir tarihte ise
                    if (DateTime.Compare(scheduledWorkPackage.InitialStartDate, assigned.StartDate) > 0)
                        scheduledWorkPackage.InitialStartDate = assigned.StartDate;
                    //assigned end date daha geç bir tarih ise 
                    if (DateTime.Compare(scheduledWorkPackage.InitialEndDate, assigned.EndDate) < 0)
                        scheduledWorkPackage.InitialEndDate = assigned.EndDate;

                    //TODO: assignedin bitiş tarihi çok geç ise bu eleman gereksiz onu hesapla
                }
                 */
            }

            var sortedQuery = from package in tempQuery
                              orderby package.ProperEmployees.Count
                              select package;

            //Siralı halde scheduledworkpackageslar geliyor..
            foreach (ScheduledWorkPackages package in sortedQuery)
            {
                //scheduled workpackageslar sıralı hale getiriliyor..
                scheduleWorkPackageQuery.Add(package);
            }

            //siralı haldeki scheduledworkpackageslerden
            foreach (ScheduledWorkPackages sortedScheduled in scheduleWorkPackageQuery)
            {
                //sirali haldeki scheduledworkpackagesler içinden
                foreach (ScheduledWorkPackages sPackage in scheduleWorkPackageQuery)
                {
                    //sırasız haldeki dependencyleri getiriliyor..
                    foreach (WorkPackage dependency in sortedScheduled.Dependency)
                    {
                        if (dependency.ID == sPackage.ID)
                        {
                            sortedScheduled.ScheduledDepedency.Add(sPackage);
                            break;
                        }
                    }
                }
            }

            return scheduleWorkPackageQuery;
        }

        public List<Assignment> assignWorkPackages()
        {

            List<ScheduledWorkPackages> scheduleQuery = createWorkPackageQuery(tempProject.PackageList);
            foreach (ScheduledWorkPackages package in scheduleQuery)
            {
                if (package.isScheduled)
                    continue;

                if (package.Dependency.Count > 0)
                {
                    foreach (ScheduledWorkPackages parent in package.ScheduledDepedency)
                    {

                        DateTime date = findStartDateInDependent(parent);
                        if (DateTime.Compare(package.InitialStartDate, date) < 0) // degistii
                        {
                            package.InitialStartDate = date.AddDays(1);
                        }
                    }
                    schedule(package);

                }
                else if (package.Dependency.Count == 0)
                {
                    schedule(package);
                }
            }

            return assignmentList;
        }

        public bool schedule(ScheduledWorkPackages package)
        {

            System.Diagnostics.Debug.WriteLine("ID: " + package.ID + "INITDate: " + package.InitialStartDate + "ENDDate: " + package.InitialEndDate);

            if (package.isScheduled) // Schedule edilen bir daha edilmesin diye.
                return false;
            if (package.ProperEmployees.Count == 0)
            {
                _Result = "HATA!!," + package.Name + " icin uygun bir atama yapılamıyor...";
                return false;
            }


            foreach (Employee employee in package.ProperEmployees)
            {
                Assignment tempAssignment = new Assignment();
                tempAssignment.StartDate = package.InitialStartDate;
                // TODO: Temp assignmentlar bir listede tutulup kontrol edilmeli !!!!

                foreach (Assignment assigned in assignmentList)
                {
                    if (employee.ID == assigned.Employee.ID)
                    {
                        if (DateTime.Compare(tempAssignment.StartDate, assigned.EndDate) < 0)
                            tempAssignment.StartDate = assigned.EndDate.AddDays(1);

                    }

                }

                //List<Assignment> probableAssignmentforEmployee = new List<Assignment>();
                //Assignment tempProbable;
                // databasedeki assignmentları kontrol eder
                //List<Assignment> assignmentToEmployee;
                //assignmentToEmployee = assignmentHandler.GetAssignmentsByEmployeeID(employee.ID);

                /* for(int i=0; i<assignmentToEmployee.Count; i++) {

                     if (assignmentToEmployee[i].EndDate.Day + 1 == assignmentToEmployee[i + 1].StartDate.Day)
                     {
                     }
                     else {
                         tempProbable = new Assignment();
                         tempProbable.StartDate = assignmentToEmployee[i].EndDate.GetDateTimeFormats;
                         tempProbable.
                    
                     }
                 }*/

                /*
                foreach (Assignment assigned in assignmentToEmployee)
                {
                    //assigned end date daha geç bir tarihte ise
                    if (DateTime.Compare(tempAssignment.StartDate, assigned.StartDate) < 0)
                        tempAssignment.EndDate = assigned.StartDate.AddDays(-1);
                    else if (DateTime.Compare(tempAssignment.StartDate, assigned.EndDate) < 0)
                        tempAssignment.StartDate = assigned.EndDate.AddDays(1);

                    //TODO: assignedin bitiş tarihi çok geç ise bu eleman gereksiz onu hesapla
                }*/
                //=====================================================================================



                //if (package.InitialStartDate.Day == 1)
                    tempAssignment.EndDate = tempAssignment.StartDate.AddDays(Math.Ceiling(package.Requirement.ManHour / employee.HourPerDay) - 1);
                //else
                    //tempAssignment.EndDate = tempAssignment.StartDate.AddDays(Math.Ceiling(package.Requirement.ManHour / employee.HourPerDay));


                //totalHourPerDay += employee.HourPerDay;





                
                tempAssignment.WorkPackage = package;
                tempAssignment.Employee = employee;
                string skillLevel=null;

                foreach (KeyValuePair<Capability, SkillLevel> capability in tempAssignment.Employee.Skills)
                {
                    if ((tempAssignment.WorkPackage.Requirement.RequirementCapability.Name).ToLower() == (capability.Key.Name).ToLower())
                    {
                        skillLevel=capability.Value.ToString();
                        break;
                    }
                }

                float high = (float)1.25;
                float low = (float) 0.75;

                if(skillLevel=="Low")
                    tempAssignment.HourPerDay = low * employee.HourPerDay;
                else if(skillLevel=="Medium")
                    tempAssignment.HourPerDay = employee.HourPerDay;
                else if(skillLevel=="High")
                    tempAssignment.HourPerDay = high * employee.HourPerDay;
                
                assignmentList.Add(tempAssignment);

            }


            var sortedassign = from assign in assignmentList
                               orderby assign.StartDate
                               select assign;

            foreach (Assignment assign in sortedassign)
            {

                if (assign.WorkPackage.ID == package.ID)
                {

                    package.Assignment.Add(assign);


                }
            }

            if (!package.arrangeAssignments()) {
                foreach (Assignment assign in assignmentList.ToList())
                {
                    if (assign.WorkPackage.ID == package.ID)
                    {
                        if (DateTime.Compare(assign.EndDate, assign.StartDate) <= 0)
                        {
                            assignmentList.Remove(assign);
                        }
                    }
                }
            }
            package.isScheduled = true;
            return true;

        }

        public DateTime findStartDateInDependent(ScheduledWorkPackages parent)
        {

            if (parent.Dependency.Count == 0)
            {
                schedule(parent);
                return parent.InitialEndDate;
            }
            else
            {
                foreach (ScheduledWorkPackages grandParent in parent.ScheduledDepedency)
                {

                    DateTime date = findStartDateInDependent(grandParent);
                    if (DateTime.Compare(parent.InitialStartDate, date) < 0)
                    {
                        parent.InitialStartDate = date.AddDays(1);
                    }
                }
                schedule(parent);
                return parent.InitialEndDate;
            }
        }
    }
}